home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / libdmalloc / stacktrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  35.8 KB  |  1,369 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.     Link with -lmld
  19. */
  20. /*
  21.     XXX THIS IS COMPLETELY WRONG AND DEFUNCT
  22.  
  23.     Old functions in this file (somebody wrote these a long time ago)
  24.     void initstacktrace(argv) -- sets up signal handlers so that signals
  25.                 SEGV,BUS,ILL,QUIT produce a stack trace
  26.                 to stdout and exit(sig_number).
  27.                 argv[0] must stick around forever.
  28.                 argv[0] must also be the exact name
  29.                 of the executable file (bogus!)
  30.     int stacktrace (filename, startpc, startsp, regs, getword)
  31.                  -- prints a stack trace.  Opens the a.out
  32.                 file called filename for symbols,
  33.                 starts with startsp and regs,
  34.                 and uses getword() to get a word
  35.                 from an address (either from memory
  36.                 or from a core file I guess).
  37.                 Closes the a.out properly (didn't before).
  38.                 Reads register variables properly (I
  39.                 think it didn't before).
  40.                 Returns 0 on success (didn't before),
  41.                 -1 on failure.
  42.     New functions:
  43.     int stacktrace_print(int skip)
  44.         Front end to stacktrace().  Prints the current stack trace.
  45.  
  46.     int simple_stacktrace_get(int skip, int n, void *trace[])
  47.         Gets a stack trace consisting soly of pc's
  48.         into the trace array.  At most n pc's are retrieved.
  49.         If skip is 0, the trace will start at the return
  50.         address from simple_stacktrace_get(); if it is 1,
  51.         it will start at return address from the calling function, etc..
  52.         The function returns the number of pc's actually retrieved.
  53.         If it got lost due to a non-stack frame pointer
  54.         (whatever that means) then the last entry in the
  55.         trace will be zero.
  56.  
  57.     int simple_stacktrace_write(int fd, char *fmt, char *executable,    
  58.                             int n, void *trace[])
  59.         Prints to fd the result of simple_stacktrace_get(), using
  60.         symbols from the file executable.  executable is not
  61.         closed (in case many stack traces need to be printed).
  62.         If NULL is passed as executable,
  63.         simple_stacktrace_get_argv0() is called to try to retrieve it.
  64.         fmt is used to print the index in the stack trace,
  65.         prepended to each line.
  66.         XXX This is not very versatile.  For example,
  67.         the caller might want to indent by a certain amount
  68.         but leave out the line numbers.  I'll think about it...
  69.  
  70.     void stacktrace_cleanup()
  71.         Closes the executable file opened by simple_stacktrace_write()
  72.         if there is one open.
  73.  
  74.     char *simple_stacktrace_get_argv0()
  75.         Attempts to get argv[0] of the currently running program.
  76.         This is not reliable unless you know the
  77.         main procedure did not overwrite its arguments.
  78.         Of course it also will not produce a valid filename
  79.         unless the program is in the current directory
  80.         or was invoked with an absolute pathname.
  81. */
  82. /*
  83.     To Do:
  84.     -- Doesn't follow past signal handler (dbx knows how).
  85.     -- Can't find some functions (dbx finds them).
  86. */
  87.  
  88. #include "stacktrace.h"
  89.  
  90.  /* ------------------------------------------------------------------ */
  91.  /* | Copyright Unpublished, MIPS Computer Systems, Inc.  All Rights | */
  92.  /* | Reserved.  This software contains proprietary and confidential | */
  93.  /* | information of MIPS and its suppliers.  Use, disclosure or     | */
  94.  /* | reproduction is prohibited without the prior express written   | */
  95.  /* | consent of MIPS.                                               | */
  96.  /* ------------------------------------------------------------------ */
  97.  /*  stacktrace.c 1.5 */
  98.  
  99. #include <stdio.h>
  100. #include <assert.h>
  101. #include <string.h>
  102. #include <unistd.h>
  103. #include <stdlib.h>
  104. #include <signal.h>
  105. #include <a.out.h>
  106. #include <ar.h>
  107. #include <ldfcn.h>    /* for definition of LDFILE and ldopen() */
  108. extern int ldreadst(LDFILE *, int); /* XXX missing from include file */
  109. extern long ldgetpd(LDFILE *ldptr, long ipd, pPDR ppd); /* XXX ditto */
  110. extern int ld_ifd_symnum(LDFILE *, long);
  111. extern char *st_str_ifd_iss(int, int);
  112. #include <sys/ptrace.h>    /* for definition of GPR_BASE */
  113. #include <exception.h>    /* for definition of find_rpd() */
  114. #include <sys/param.h>    /* for definition of MAXPATHLEN */
  115. #include <sex.h>
  116.  
  117. #ifdef SA_NODEFER    /* this is in signal.h in IRIX5 but not IRIX4 */
  118. #define IRIX5
  119. #endif /* SA_NODEFER */
  120.  
  121. #ifdef IRIX5
  122. #include <rld_interface.h>
  123. #endif /* IRIX5 */
  124.  
  125.  
  126. static int ipd_adr (LDFILE *ldptr, unsigned long adr);
  127. static int ipd_adr_all(int nldptrs, LDFILE *ldptrs[], long ldoffsets[], LDFILE **Whichldptr, long *Whichoffset, long adr);
  128. static long get_ldptr_offset(LDFILE *ldptr);
  129. static LDFILE *ldptrs[100];
  130. static int nldptrs = 0;
  131.  
  132. char ldfilename[4096 * 4];    /* must be big enough to hold all the names */ 
  133. char *ldfilename_end = ldfilename;    /* after end of last name */
  134. char *ldfilenames[100];
  135. long ldoffsets[100];            /* add to symbol to get address */
  136.  
  137. static char *myname;
  138.  
  139. static agetword(addr)
  140. unsigned addr;
  141. {
  142.     return *(int *)addr;
  143. }
  144.  
  145. #define myprintf printf
  146.  
  147. static char *regnames[] = {
  148.         "r0/zero",    "r1/at",    "r2/v0",    "r3/v1",
  149.         "r4/a0",    "r5/a1",    "r6/a2",    "r7/a3",
  150.         "r8/t0",    "r9/t1",    "r10/t2",    "r11/t3",
  151.         "r12/t4",    "r13/t5",    "r14/t6",    "r15/t7",
  152.         "r16/s0",    "r17/s1",    "r18/s2",    "r19/s3",
  153.         "r20/s4",    "r21/s5",    "r22/s6",    "r23/s7",
  154.         "r24/t8",    "r25/t9",    "r26/k0",    "r27/k1",
  155.         "r28/gp",    "r29/sp",    "r30/fp",    "r31/ra",
  156. };
  157. /*===================== New stuff starts here ================================*/
  158.  
  159.        /* just to keep my head clear-- changing to void * will take some work */
  160. typedef long address;
  161. #define numberof(sextoys) (sizeof(sextoys)/sizeof(*(sextoys)))
  162. #define streq(s,t) (strcmp(s, t) == 0)
  163. #define BITS(A)         (sizeof(A) * 8)
  164. #define BIT(A,i)        (((A)[(i)/BITS(*(A))] >> ((i)%BITS(*(A)))) & 1)
  165. #define A0 4
  166. #define A1 5
  167. #define SP 29
  168. #define RA 31
  169.  
  170. #ifdef DO_IT_IN_C
  171. /*
  172.  * Don't laugh, it works... (but it's really slow).
  173.  */
  174. static address *_startpc, *_startsp, *_regs;
  175. static void
  176. _get_startpc_and_startsp(sig, code, scp)
  177. int sig, code;
  178. struct sigcontext *scp;
  179. {
  180.     *_startpc = scp->sc_pc;
  181.     *_startsp = scp->sc_regs[GPR_BASE+SP];
  182.     bcopy(scp->sc_regs+GPR_BASE, _regs, 32 * sizeof(*_regs));
  183. }
  184. static int
  185. get_startpc_and_startsp_and_regs(Startpc, Startsp, regs)
  186. address *Startpc, *Startsp, regs[32];
  187. {
  188.     /* to make life easier, use SIGHUP because dbx ignores it */
  189.     void (*ohandler)() = signal(SIGHUP, _get_startpc_and_startsp);
  190.     _startpc = Startpc;
  191.     _startsp = Startsp;
  192.     _regs = regs;
  193.     kill(getpid(), SIGHUP);
  194.     signal(SIGHUP, ohandler);
  195.     return 3;    /* # of extra levels to skip */
  196. }
  197. #endif /* DO_IT_IN_C */
  198.  
  199. #define XXX_SHOWMASK    /* keep this here in case I get curious */
  200. #ifdef XXX_SHOWMASK
  201. #include <stdio.h>
  202. static void showmask(address pc, address sp, address fp, unsigned long mask)
  203. {
  204.     int i;
  205.     int printed = 0;
  206.     fprintf(stderr, "pc=%#x, fp=%#x, sp=%#x, mask=%#x(", pc, sp, fp, mask);
  207.     for (i = 0; i < 32; ++i)
  208.     if (BIT(&mask, i)) {
  209.         if (printed)
  210.         fprintf(stderr, ", ");
  211.         fprintf(stderr, "%d", i);
  212.         printed = 1;
  213.     }
  214.     fprintf(stderr, ")\n");
  215. }
  216.  
  217. static char *
  218. masktoa(mask)
  219. {
  220.     int i, printed = 0;
  221.     static char buf[32*3];
  222.     buf[0] = 0;
  223.     for (i = 0; i < 32; ++i)
  224.     if (BIT(&mask, i)) {
  225.         if (printed)
  226.         sprintf(buf+strlen(buf), ",");
  227.         sprintf(buf+strlen(buf), "%d", i);
  228.         printed = 1;
  229.     }
  230.     return buf;
  231. }
  232.  
  233. #endif /* XXX_SHOWMASK */
  234.  
  235. /* use kipp's find_runtime_pdr, since libexc's find_pdr has
  236.    assertions and its cache size is too small. */
  237. #ifndef PDR_CACHE_SIZE
  238. #define PDR_CACHE_SIZE  1024
  239. #endif
  240.  
  241.  
  242. #ifdef DEFUNCT
  243. static RPDR* cache[PDR_CACHE_SIZE];
  244. static RPDR* find_runtime_pdr(unsigned long pc)
  245. {
  246.     RPDR *p, *end;
  247.     u_int base, limit, hash, midPoint;
  248.  
  249.     /* see if pc is in cache */
  250.     hash = (pc >> 2) & (PDR_CACHE_SIZE-1);
  251.     end = &_procedure_table[PSIZE];
  252.     p = cache[hash];
  253.     if (p && (pc >= p->adr)) {
  254.     if (p+1 < end) {
  255.         if (pc < (p+1)->adr) {
  256.         return p;
  257.         }
  258.     } else {
  259.         return p;
  260.     }
  261.     }
  262.  
  263.     /* do a binary search through the pdr table */
  264.     base = 0;
  265.     limit = PSIZE-1;
  266.     while (base <= limit) {
  267.     midPoint = (base + limit)>>1;
  268.     p = &_procedure_table[midPoint];
  269.     if (pc < p->adr) {
  270.         limit = midPoint - 1;
  271.     } else {
  272.         if (p+1 < end) {
  273.         if (pc < (p+1)->adr) {
  274.             cache[hash] = p;
  275.             return p;
  276.         }
  277.         } else {
  278.         cache[hash] = p;
  279.         return p;
  280.         }
  281.         base = midPoint + 1;
  282.     }
  283.     }
  284.     return 0;
  285. }
  286. #endif /* DEFUNCT */
  287.  
  288. static RPDR *
  289. find_runtime_pdr(unsigned long pc)
  290. {
  291.     static RPDR* cache[PDR_CACHE_SIZE];
  292.     RPDR *p, *first, *last;
  293.     unsigned long lo, hi, mid, hash;
  294.  
  295.     hash = (pc/4) & (PDR_CACHE_SIZE-1);
  296.     first = &_procedure_table[0];
  297.     last = &_procedure_table[PSIZE-1];
  298.     p = cache[hash];
  299.  
  300.     /* see if pc is in cache */
  301.     if (p)
  302.     if (pc >= p->adr && (p == last || pc < (p+1)->adr))
  303.         return p;
  304.     /* otherwise there was a collision and the wrong thing is in the cache*/
  305.  
  306.     /* so we don't need to be paranoid about exceeding bounds... */
  307.     if (pc < (first+1)->adr)
  308.     return cache[hash] = first;
  309.     if (pc >= last->adr)
  310.     return cache[hash] = last;
  311.  
  312.     /* do a binary search through the pdr table */
  313.     lo = 1;        /* always lowest possible */
  314.     hi = PSIZE-2;    /* always highest possible */
  315.     while (lo <= hi) {
  316.     mid = (lo + hi) / 2;
  317.     p = &_procedure_table[mid];
  318.     if (pc < p->adr)
  319.         hi = mid - 1;
  320.     else if (pc >= (p+1)->adr)
  321.         lo = mid+1;
  322.     else
  323.         return cache[hash] = p;
  324.     }
  325.  
  326.     /* if we get here, the table is out of order
  327.        and this algorithm needs to be rethought-- abort. */
  328.     assert(lo <= hi);
  329. }
  330.  
  331. #define GETWORD(addr) (*(address *)(addr))
  332. /*
  333.  * The following routine just gets the pc's of a stack trace of depth at most n,
  334.  * without looking up symbol names or anything.
  335.  * Returns the number of pc's actually retrieved.
  336.  * If it gets lost (due to non-sp frame pointer or bad pc)
  337.  * the last entry filled in will be zeros.
  338.  */
  339. static int
  340. notsosimple_stacktrace_get(int skip, int n, void *pcs[],
  341.                         void *sps[],
  342.                         void *fps[],
  343.                         address regs[32])
  344. {
  345.     extern address _stacktrace_get_pc(),
  346.            _stacktrace_get_sp(), _stacktrace_get_regs(address *);
  347.     address sp,pc,fp, regsbuf[32], regmask;
  348.     int i;
  349.     int ireg,nreg;
  350.  
  351.     static int use_find_rpd = -1;
  352.     if (use_find_rpd == -1)
  353.     use_find_rpd = !!getenv("_USE_FIND_RPD");    /* XXX */
  354.  
  355.     if (!n)
  356.     return 0;        /* don't waste time */
  357.  
  358.     if (!regs)
  359.     regs = regsbuf;
  360.  
  361. #ifdef DO_IT_IN_C
  362.     skip += 1 + get_startpc_and_startsp_and_regs(&pc, &sp, regs);
  363. #else
  364.     pc = _stacktrace_get_pc();
  365.     sp = _stacktrace_get_sp();
  366.     _stacktrace_get_regs(regs);
  367.     skip++;
  368. #endif
  369.  
  370.     for (fp = 1, i = -skip; sp != 0 && fp != 0 && pc != 0 && i < n; i++) {
  371.     /*
  372.      * This is balogna... we should be able to figure out this
  373.      * stuff just by looking at the local stack
  374.      */
  375.     struct runtime_pdr *prpd;
  376.  
  377.     /*
  378.      * bleah!  not only that, but find_rpd() has assertions!!
  379.      * So we gotta circumvent them by using our own version, which is faster anyway.
  380.      */
  381.  
  382.  
  383.     if (use_find_rpd)
  384.         prpd = find_rpd(pc);
  385.     else
  386.         prpd = find_runtime_pdr(pc);
  387.  
  388.     if (!prpd || prpd == (struct runtime_pdr *)-1) {
  389.         static int complained_already = 0;
  390.         if (!complained_already) {
  391.         fprintf(stderr,
  392.               "Can't find runtime procedure descriptor for %#x!\n", pc);
  393.         fprintf(stderr, "You're using shared libraries, AREN'T YOU?\n");
  394.         }
  395.         /* fill in the last entry with NULL so it's evident that something went wrong */
  396.         if (i >= 0) {
  397.         if (pcs) pcs[i] = NULL;
  398.         if (sps) sps[i] = NULL;
  399.         if (fps) fps[i] = NULL;
  400.         }
  401.         i++;
  402.         break;
  403.     }
  404.  
  405.     if (prpd->framereg != GPR_BASE+29) {    /* XXX this happens-- should try to understand */
  406.         /*
  407.         myprintf("%#x has a non-sp framereg (%d)\n", prpd->adr,
  408.         prpd->framereg);
  409.         */
  410.         if (i >= 0) {
  411.         if (pcs) pcs[i] = NULL;
  412.         if (sps) sps[i] = NULL;
  413.         if (fps) fps[i] = NULL;
  414.         }
  415.         i++;
  416.         break;
  417.     }
  418.  
  419.     fp = sp + prpd->frameoffset;
  420.  
  421.     if (i >= 0) {
  422.         if (pcs) pcs[i] = (void *)((int *)pc-1);
  423.         if (sps) sps[i] = (void *)sp;
  424.         if (fps) fps[i] = (void *)fp;
  425.     }
  426.  
  427. #ifdef XXX_SHOWMASK
  428.     {
  429.         static int env_showmask = -1;
  430.         if (env_showmask == -1)
  431.         env_showmask = !!getenv("_STACKTRACE_SHOWMASK"); /* XXX */
  432.         if (env_showmask)
  433.         showmask(pc, sp, fp, prpd->regmask);
  434.     }
  435. #endif /* XXX_SHOWMASK */
  436.  
  437. next:
  438.     sp = fp;
  439.  
  440.     /* restore regs */
  441.     regmask = prpd->regmask;
  442.     for (nreg = 0, ireg = 31; ireg >=0; ireg--) {
  443.         /* if (BIT(&prpd->regmask, ireg) != 0) */
  444.         if (regmask & (1<<ireg)) {
  445.         regs[ireg] = GETWORD(fp+prpd->regoffset-(nreg*4));
  446.         nreg++;
  447.         }
  448.         if (regs == regsbuf)
  449.         break;    /* caller doesn't want regs; all we care about is RA */
  450.     }
  451.     if (prpd->pcreg == 0)
  452.         pc = GETWORD(fp-4);
  453.     else
  454.         pc = regs[prpd->pcreg];    /* always RA if anything */
  455.     } /* for */
  456.     return i < 0 ? 0 : i;
  457. }
  458.  
  459. extern int
  460. stacktrace_get(int skip, int n, void *pcs[])
  461. {
  462.     return notsosimple_stacktrace_get(skip+1, n, pcs, NULL,NULL, NULL);
  463. }
  464.  
  465. #ifdef IRIX5
  466. #include <dem.h>
  467. #else /* IRIX4 */
  468. #define MAXDBUF 4096
  469. #endif /* IRIX4 */
  470.  
  471. static void
  472. funname_to_human_readable_funname(char *fun, char *hrfun, int siz)
  473. {
  474.     /*
  475.     Sherwood uses demangle(in, out), returning 0 on success, -1 on failure.
  476.     4.0.5 uses demangle(in), returning the result or NULL on failure.
  477.     Let's make this work for both...
  478.      */
  479.     char buf[MAXDBUF];
  480.     int result;
  481.     if (siz > MAXDBUF)
  482.     siz = MAXDBUF;
  483.  
  484.     result = demangle(fun, buf);
  485.     if (result != 0 && result != -1)    /* then this must be 4.0.5 */
  486.     strncpy(hrfun, (char *)result, siz-1);
  487.     else
  488.     strncpy(hrfun, buf, siz-1);
  489.     hrfun[siz-1] = 0;
  490. }
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502. /*=============== Begin some portable stuff ==============================*/
  503. /*===== (someday, separate out the functions that are machine-specific) ==*/
  504.  
  505. /* main() can alter or clobber its argv, so it may
  506.    be impossible to get argv[0] by tracing the stack.
  507.    Allow the application to tell us what argv[0] is explicitly
  508.    if it is going to be so barbaric.
  509. */
  510. static char saved_argv0[MAXPATHLEN+1];
  511. static char saved_executable[MAXPATHLEN+1];
  512.  
  513. extern void
  514. stacktrace_set_executable(const char *executable)
  515. {
  516.     if (executable)
  517.     strncpy(saved_executable, executable, MAXPATHLEN);
  518.     else
  519.     saved_executable[0] = '\0';
  520. }
  521.  
  522. static char *
  523. find_in_path(char *path, char *filename, int mode, char fullname[MAXPATHLEN+1])
  524. {
  525.     char *p = path, *dir;
  526.  
  527.     if (strchr(filename, '/'))
  528.     return strncpy(fullname, filename, MAXPATHLEN);
  529.     else {
  530.     for (dir = p; dir && *dir; dir = p) {
  531.         while (*p && *p != ':')
  532.         p++;
  533.         if (!strncmp(dir, ".", p - dir)) /* also satisfied if p==dir */
  534.         strcpy(fullname, filename);
  535.         else
  536.         sprintf(fullname, "%.*s/%s", p - dir, dir, filename);
  537.         /* not right under setuid, but FUCK IT */
  538.         if (access(fullname, mode) != -1)
  539.         return fullname;
  540.         if (*p)
  541.         p++;
  542.     }
  543.     fullname[0] = '\0';
  544.     return NULL;
  545.     }
  546. }
  547.  
  548. extern char *
  549. stacktrace_get_executable()
  550. {
  551.     char *argv0;
  552.  
  553.     if (saved_executable[0])
  554.     return saved_executable;
  555.     
  556.     argv0 = stacktrace_get_argv0();
  557.  
  558.     if (argv0 && argv0[0]) {
  559.     return find_in_path(getenv("PATH"), argv0, X_OK, saved_executable);
  560.     } else
  561.     return NULL;
  562. }
  563.  
  564. extern void
  565. stacktrace_set_argv0(const char *argv0)
  566. {
  567.     if (argv0)
  568.     strncpy(saved_argv0, argv0, MAXPATHLEN);
  569.     else
  570.     saved_argv0[0] = '\0';
  571.     saved_executable[0] = '\0';    /* XXX ? should do this? should recalc? */
  572. }
  573. /*========================== End of portable stuff =========================*/
  574. #define INRANGE(foo,bar,baz) ((foo(bar))&&((bar)baz))
  575. #define STACK_END 0x80000000
  576. #define IS_STACK_ADDRESS(p) \
  577.     INRANGE((unsigned long)(p) <, *(unsigned long *)(p), < STACK_END)
  578. extern char *
  579. stacktrace_get_argv0()
  580. {
  581.     int argc;
  582.     unsigned long *p;
  583.  
  584.     if (saved_argv0[0])
  585.     return saved_argv0;
  586.  
  587.     if (getenv("_STACKTRACE_ARGV0"))
  588.     return strcpy(saved_argv0, getenv("_STACKTRACE_ARGV0"));
  589.  
  590.     /*
  591.     Assume the stack looks like this (walking backwards from the end)
  592.         zeros
  593.         garbage
  594.         env strings
  595.         argv strings
  596.         garbage
  597.         zero (terminating envp array)
  598.         envp array
  599.         zero (terminating argv array)
  600.         argv array
  601.         argc
  602.     */
  603.  
  604.     p = (unsigned long *)STACK_END - 1;    /* end of stack, hopefully */
  605.  
  606.     while (!IS_STACK_ADDRESS(p))
  607.     p--;
  608.  
  609.     /* p is now pointing at last element of envp array */
  610.     while (*p)    /* not IS_STACK_ADDRESS(p), since putenv() messes that up */
  611.     p--;
  612.  
  613.     /* p is now hopefully poing at the zero terminating the argv array */
  614.     if (*p != 0)
  615.     return NULL;    /* shouldn't happen */
  616.  
  617.     p--;
  618.  
  619.     /* p is now pointing at the last element of argv array */
  620.  
  621.     argc = 0;
  622.     while (IS_STACK_ADDRESS(p))
  623.     argc++, p--;
  624.  
  625.     /* p is now pointing at something which should contain argc */
  626.     if (*p != argc)
  627.     return 0;    /* shouldn't happen */
  628.  
  629.     if (argc == 0) {
  630.     /* fprintf(stderr, "Program was run with no args???\n"); */
  631.     return 0;
  632.     }
  633.  
  634.     p++;
  635.  
  636.     /* p is now pointing at first element of argv array */
  637.  
  638.     assert(strlen((char *)p) + 1 <= sizeof(saved_argv0));
  639.     return strcpy(saved_argv0, (char *)*p);
  640. }
  641.  
  642. extern void
  643. stacktrace_cleanup()
  644. {
  645.     while (nldptrs > 0) {
  646.     nldptrs--;
  647.  
  648.     fprintf(stderr, "Closing \"%s\"... ", ldfilenames[nldptrs]);
  649.  
  650. /* XXX ldaclose leaks like a sieve!  (see leak2 program and bug #176726)
  651.    ldclose doesn't leak quite as badly... */
  652. if (!getenv("_STACKTRACE_USE_LDACLOSE"))
  653.     ldclose(ldptrs[nldptrs]);
  654. else
  655.  
  656.     ldaclose(ldptrs[nldptrs]);
  657.     ldptrs[nldptrs] = NULL;
  658.  
  659.     fprintf(stderr, "done.\n");
  660.     }
  661.  
  662.     ldfilename[0] = '\0';
  663.     ldfilename_end = ldfilename;
  664. }
  665.  
  666. static char *
  667. save_ldfilename(char *name)
  668. {
  669.     char *old_end = ldfilename_end;
  670.     ldfilename_end += strlen(name) + 1;
  671.     assert(ldfilename_end <= ldfilename + sizeof(ldfilename));
  672.     strcpy(old_end, name);
  673.     return old_end;
  674. }
  675.  
  676. /*
  677.  * Open executable and all rld libs.
  678.  * (the name is defunct; it is left over from when
  679.  * we opened the executable and read its library list
  680.  * rather than asking rld)
  681.  */
  682. static int
  683. add_object_and_libs(char *filename, int do_children)
  684. {
  685.     fprintf(stderr, "Opening \"%s\"... ", filename);
  686.     assert(nldptrs < numberof(ldptrs));
  687.     if (!(ldptrs[nldptrs] = ldopen(filename, NULL))) {
  688.     fprintf(stderr, "Can't open object \"%s\"\n", filename);
  689.     return 0;    /* failure */
  690.     }
  691.     fprintf(stderr, "done.\n");
  692.     ldfilenames[nldptrs] = save_ldfilename(filename);
  693.     ldoffsets[nldptrs] = 0;    /* main executable doesn't get relocated */
  694.     nldptrs++;
  695.  
  696. #ifdef IRIX5
  697.     if (do_children) {
  698.     char *so_name;
  699.     for (so_name = (char *)_rld_new_interface(_RLD_FIRST_PATHNAME);
  700.          so_name;
  701.          so_name = (char *)_rld_new_interface(_RLD_NEXT_PATHNAME)) {
  702.         if (streq(so_name, "MAIN")) {
  703.         fprintf(stderr, "Skipping MAIN in dso list.\n");
  704.         continue;
  705.         }
  706.         fprintf(stderr, "Opening \"%s\" ...", so_name);
  707.         assert(nldptrs < numberof(ldptrs));
  708.         if (ldptrs[nldptrs] = ldopen(so_name, NULL)) {
  709.         ldfilenames[nldptrs] = save_ldfilename(so_name);
  710.         ldoffsets[nldptrs] = get_ldptr_offset(ldptrs[nldptrs]);
  711.  
  712.         nldptrs++;
  713.         } else
  714.         fprintf(stderr, "(couldn't open %s)", so_name);
  715.         fprintf(stderr, "done.\n");
  716.     }
  717.     }
  718. #endif /* IRIX5 */
  719.  
  720.     return 1;    /* success-- opened at least this one */
  721. }
  722.  
  723. /*
  724.     XXX must see how expensive this is, and maybe do it less often...
  725. */
  726. static int
  727. ldfiles_are_in_sync_with_rld(char *assumed_rld_main_executable)
  728. {
  729. #ifdef IRIX5
  730.     int i;
  731.     char *so_name;
  732.  
  733.     for (i = 0, so_name = (char *)_rld_new_interface(_RLD_FIRST_PATHNAME);
  734.      i < nldptrs && so_name;
  735.      i++, so_name = (char *)_rld_new_interface(_RLD_NEXT_PATHNAME)) {
  736.     if (streq(so_name, "MAIN"))
  737.         so_name = assumed_rld_main_executable;
  738.     if (!streq(so_name, ldfilenames[i]))
  739.         break;
  740.     }
  741.     if (i < nldptrs || so_name)
  742.     return 0;
  743.     return 1;
  744. #else /* IRIX4 */
  745.     return nldptrs > 0 && streq(ldfilename, assumed_rld_main_executable);
  746. #endif /* IRIX4 */
  747. }
  748.  
  749. static int
  750. simple_stacktrace_write_init(char *filename)
  751. {
  752.     if (!filename)
  753.     return 0;    /* failure */
  754.     if (!ldfiles_are_in_sync_with_rld(filename)) {
  755.     if (nldptrs)
  756.         fprintf(stderr, "Symbol table out of sync; reinitializing.\n");
  757.     stacktrace_cleanup();
  758.  
  759.     add_object_and_libs(filename, 1);
  760.     }
  761.     if (nldptrs == 0)
  762.     return 0;    /* failure */
  763.  
  764.     
  765.     return 1;    /* success */
  766. }
  767.  
  768. extern int
  769. simple_stacktrace_write(int fd, char *fmt, char *filename, int n, void *trace[])
  770. {
  771.     LDFILE *ldptr;
  772.     char nicename[1000];
  773.     char buf[MAXPATHLEN+100];
  774.     address pc;
  775.     int i, iproc, ifd;
  776.     struct pdr pd;
  777.     SYMR asym;
  778.     char *pname;
  779.     int line;
  780.     long offset;
  781.  
  782.     if (n <= 0)
  783.     return 0;    /* success, even if we can't open the file */
  784.  
  785.     buf[0] = 0;
  786.  
  787.     if (filename == NULL)
  788.     filename = stacktrace_get_executable();
  789.     if (filename == NULL) {
  790.     sprintf(buf+strlen(buf), "(pid=%d, cannot find name of executable, setenv _STACKTRACE_ARGV0 filename)\n", getpid());
  791.     write(fd, buf, strlen(buf));
  792.     return -1;
  793.     }
  794.  
  795.     if (!simple_stacktrace_write_init(filename)) {
  796.     sprintf(buf+strlen(buf), "(cannot read in %s)", filename);
  797.     write(fd, buf, strlen(buf));
  798.     return -1;    /* failure */
  799.     } 
  800.  
  801.     if (!fmt)
  802.     fmt = "%4d ";
  803.     for (i = 0; i < n; ++i) {
  804.     sprintf(buf, fmt, i);
  805.  
  806.     pc = (address) trace[i];
  807.     iproc = ipd_adr_all(nldptrs, ldptrs, ldoffsets, &ldptr, &offset, pc);
  808.     if (ldgetpd(ldptr, iproc, &pd) == FAILURE) {
  809.         sprintf(buf+strlen(buf), "(ldgetpd failed)\n");
  810.         write(fd, buf, strlen(buf));
  811.         continue;
  812.     }
  813.  
  814.     if (ldtbread(ldptr,pd.isym,&asym) == FAILURE) {
  815.         sprintf(buf+strlen(buf), "(cannot read symbol %d)\n", pd.isym);
  816.         write(fd, buf, strlen(buf));
  817.         continue;
  818.     }
  819.  
  820.     pname = (char *)ldgetname(ldptr, &asym);
  821.     if (pname == NULL) {
  822.         sprintf(buf+strlen(buf), "(ldgetname failed)\n");
  823.         write(fd, buf, strlen(buf));
  824.         pname = "???";
  825.     }
  826.  
  827.     ifd = ld_ifd_symnum(ldptr, pd.isym);
  828.  
  829.     funname_to_human_readable_funname(pname, nicename, sizeof(nicename));
  830.     sprintf(buf+strlen(buf), "%s(", nicename);
  831.  
  832.     if (pd.iline+((pc-pd.adr)/4) > SYMTAB(ldptr)->hdr.ilineMax)
  833.         line = -1;
  834.     else
  835.         line = (int)SYMTAB(ldptr)->pline[pd.iline+((pc-pd.adr)/4)];
  836.         
  837.     sprintf(buf+strlen(buf), ") [%s:%d, 0x%x]\n", st_str_ifd_iss(ifd, 1),
  838.         line,
  839.         pc);
  840.     write(fd, buf, strlen(buf));
  841.     }
  842.     return 0;        /* success */
  843. }
  844.  
  845.  
  846. /*
  847.  * Get function,file,line from a pc
  848.  */
  849. extern void
  850. stacktrace_get_ffl(void *_pc, char *fun, char *file, int *line,
  851.               int funbufsiz, int filebufsiz)
  852. {
  853.     address pc = (address) _pc;
  854.     char buf[100];
  855.     struct pdr pd;
  856.     SYMR asym;
  857.     int iproc, ifd;
  858.     char *pname;
  859.     LDFILE *ldptr;
  860.     long offset;
  861.  
  862.     if (fun && funbufsiz > 0) fun[0] = fun[funbufsiz-1] = '\0';
  863.     if (file && filebufsiz > 0) file[0] = file[filebufsiz-1] = '\0';
  864.     if (line) *line = -1;
  865.  
  866.     if (!simple_stacktrace_write_init(stacktrace_get_executable())) {
  867.         /* XXX do a descriptive error message! */
  868.         sprintf(buf, "(couldn't get symbol table???)");
  869.         strncpy(fun?fun:file?file:buf, buf,
  870.            (fun?funbufsiz:file?filebufsiz:numberof(buf)) - 1);
  871.         return;
  872.     }
  873.  
  874.     iproc = ipd_adr_all(nldptrs, ldptrs, ldoffsets, &ldptr, &offset, pc);
  875.     if (ldgetpd(ldptr, iproc, &pd) == FAILURE) {
  876.     sprintf(buf, "(ldgetpd failed)");
  877.     strncpy(fun?fun:file?file:buf, buf,
  878.            (fun?funbufsiz:file?filebufsiz:numberof(buf)) - 1);
  879.     return;
  880.     }
  881.     if (pd.isym == -1) {
  882.     sprintf(buf, "???(ipd_adr=%d)", ipd_adr(ldptr, pc-offset));
  883.     strncpy(fun?fun:file?file:buf, buf,
  884.            (fun?funbufsiz:file?filebufsiz:numberof(buf)) - 1);
  885.     return;
  886.     }
  887.  
  888.     if (fun) {
  889.     if (ldtbread(ldptr,pd.isym,&asym) == FAILURE) {
  890.         sprintf(buf, "(cannot read symbol %d)\n", pd.isym);
  891.         strncpy(fun, buf, funbufsiz-1);
  892.     } else if ((pname = (char *)ldgetname(ldptr, &asym)) == NULL) {
  893.         sprintf(buf, "(ldgetname failed)\n");
  894.         strncpy(fun, buf, funbufsiz-1);
  895.     } else {
  896.         funname_to_human_readable_funname(pname, fun, funbufsiz-1);
  897.         if (getenv("_DUMP_PROCEDURE_TABLE"))
  898.         sprintf(fun+strlen(fun), "{{{%d}}}", ipd_adr(ldptr, pc-offset));
  899.     }
  900.     }
  901.  
  902.     if (file) {
  903.     ifd = ld_ifd_symnum(ldptr, pd.isym);
  904.     strncpy(file, (char *)st_str_ifd_iss(ifd, 1), filebufsiz-1);
  905.     }
  906.  
  907.     if (line)
  908.     if (pd.iline+((pc-offset-pd.adr)/4) > SYMTAB(ldptr)->hdr.ilineMax)
  909.         *line = -1;
  910.     else
  911.         *line = (int)SYMTAB(ldptr)->pline[pd.iline+((pc-offset-pd.adr)/4)];
  912. }
  913.  
  914. /* real easy front end to stacktrace */
  915. extern int
  916. stacktrace_print(int skip)
  917. {
  918.     void *pcs[1], *sps[1];
  919.     address regs[32];
  920.     int n;
  921.     n = notsosimple_stacktrace_get(skip+1, 1, pcs, sps, NULL, regs);
  922.     if (n == 1)
  923.     return stacktrace(stacktrace_get_executable(),
  924.                   (int)pcs[0], (int)sps[0], (int *)regs,
  925.                   agetword);
  926.     else
  927.     return -1;
  928. }
  929.  
  930. extern int
  931. simple_stacktrace_print(int fd, char *fmt, int skip, int n)
  932. {
  933.     void *trace[1000];
  934.     if (n < 0 || n > numberof(trace))
  935.     n = numberof(trace);
  936.     n = stacktrace_get(skip, n, trace);
  937.     if (n < 0)
  938.     return n;
  939.     return simple_stacktrace_write(fd, fmt, NULL, n, trace);
  940. }
  941.  
  942.  
  943.  
  944. /*================== Begin stuff I found in old dbx source ==================*/
  945.  
  946.  
  947.  
  948. /*
  949.     The rest of this file is adapted from stuff I found
  950.     in old dbx source.
  951.     It doesn't demangle, but it does print function arguments (crudely)
  952.     when printing the stack trace.
  953.     Also, the above stuff uses ipd_adr() from below.
  954. */
  955.  
  956. extern int
  957. stacktrace(filename, startpc, startsp, regs, getword)
  958. char * filename;
  959. int *regs;
  960. int (*getword)(unsigned);
  961. {
  962.     char nicename[1000];
  963.     LDFILE *ldptr;
  964.     unsigned sp,pc,fp,istack,value;
  965.     int isym,ifd,ireg,nreg;
  966.     char *pname;
  967.     SYMR asym;
  968.     PDR apd;
  969.     pPDR ppd = &apd;
  970.     AUXU aux,auxpc,*ldgetaux(LDFILE *, long);
  971.     int hostsex = gethostsex();
  972.     int i,j;
  973.  
  974.     myprintf("Registers on entry:\n");
  975.     for (i = 0; i < 32; i += 3) {
  976.         for (j = i; j < 32 && j < i+3; j++)
  977.             myprintf("%s: 0x%08x\t", regnames[j], regs[j]);
  978.         myprintf("\n");
  979.     }
  980.  
  981.     auxpc.ti.bt = btUChar;
  982.     auxpc.ti.tq0 = tqPtr;
  983.  
  984.     ldptr = ldopen(filename, NULL);
  985.     if (ldptr == NULL) {
  986.     myprintf("cannot read in %s", filename);
  987.     return (-1);
  988.     } /* if */
  989.  
  990.     myprintf("Stack trace -- last called first\n");
  991.     for (pc = startpc, sp = startsp, fp = 1, istack = 0; sp != 0 && fp != 0 && pc != 0; istack++) {
  992.     ldgetpd(ldptr, ipd_adr(ldptr, pc), ppd);
  993.     isym = ppd->isym;
  994.     if (ldtbread(ldptr,isym,&asym) == FAILURE) {
  995.         myprintf("cannot read %d symbol\n", ppd->isym);
  996.         goto next;
  997.     } /* if */
  998.     pname = (char *)ldgetname(ldptr, &asym);
  999.     funname_to_human_readable_funname(pname, nicename, sizeof(nicename));
  1000.     if (ppd->framereg != GPR_BASE+29) {
  1001.         myprintf("%s has a non-sp framereg (%d)\n", nicename,
  1002.         ppd->framereg);
  1003.         ldaclose(ldptr);
  1004.         return (-1);
  1005.     } /* if */
  1006.  
  1007.     ifd = ld_ifd_symnum(ldptr, ppd->isym);
  1008.     fp = sp + ppd->frameoffset;
  1009.     myprintf("%4d %s(", istack, nicename);
  1010.     if (asym.index == indexNil) {
  1011.         myprintf ("0x%x, 0x%x, 0x%x, 0x%x", (*getword)(fp), (*getword)(fp+4), 
  1012.         (*getword)(fp+8), (*getword)(fp+12));
  1013.     } else {
  1014.         do {
  1015.         if (ldtbread(ldptr, ++isym, &asym) == FAILURE)
  1016.             break;
  1017.         if (asym.st == stBlock || asym.st == stEnd || asym.st == stProc
  1018.             || asym.st == stStaticProc)
  1019.             break;
  1020.         if (asym.st != stParam)
  1021.             continue;
  1022.         if (isym != ppd->isym+1)
  1023.             myprintf(", ");
  1024.         myprintf("%s = ", ldgetname(ldptr, &asym));
  1025.         if (asym.sc == scAbs)
  1026.             myprintf("%d", value=(*getword)(fp+asym.value));
  1027.         else if (asym.sc == scRegister && asym.value < 32)
  1028.             myprintf("%d", value=regs[asym.value]);
  1029.         else if (asym.sc == scVarRegister && asym.value < 32)
  1030.             myprintf("(*%d) %d", regs[asym.value], value=(*getword)(regs[asym.value]));
  1031.         else if (asym.sc == scVar) {
  1032.             value = (*getword)(fp+asym.value);
  1033.             myprintf("(*%d) %d", value=(*getword)(value));
  1034.         } /* if */
  1035.         if (asym.index != indexNil) {
  1036.             aux = *ldgetaux(ldptr, asym.index);
  1037.             if (PFD(ldptr)[ifd].fBigendian != (hostsex == BIGENDIAN))
  1038.             swap_aux(&aux, ST_AUX_TIR, hostsex);
  1039.             if (aux.isym == auxpc.isym) {
  1040.             int j, buf[11];
  1041.             for (j = 0; j < 10; j++)
  1042.                 buf[j] = (*getword)(value + (j*4));
  1043.             buf[11] = 0;
  1044.             myprintf (" \"%s\"", buf);
  1045.             } /* if */
  1046.         } /* if */
  1047.         } while (isym < PFD(ldptr)[ifd].csym + PFD(ldptr)[ifd].isymBase);
  1048.     } /* if */
  1049.  
  1050. if (getenv("_STACKTRACE_VERBOSE"))    /* XXX clean this up */
  1051.     myprintf (") [%s:%d, pc=0x%x, sp=0x%x, fp=0x%x, mask=%s]\n", st_str_ifd_iss(ifd, 1),
  1052.         SYMTAB(ldptr)->pline[ppd->iline+((pc-ppd->adr)/4)],
  1053.         pc, sp, fp, masktoa(ppd->regmask));
  1054. else
  1055.     myprintf (") [%s:%d, 0x%x]\n", st_str_ifd_iss(ifd, 1),
  1056.         SYMTAB(ldptr)->pline[ppd->iline+((pc-ppd->adr)/4)],
  1057.         pc);
  1058.  
  1059.     /* set up for next time */
  1060. next:
  1061.     sp = fp;
  1062.     /* restore regs */
  1063.     for (nreg = 0, ireg = 31; ireg >=0; ireg--) {
  1064.         if (((1<<ireg)&ppd->regmask) != 0) {
  1065.         regs[ireg] = (*getword)(fp+ppd->regoffset-(nreg*4));
  1066.         /*
  1067.          * NOTE: The original code was missing the following line.
  1068.          * It didn't get us lost (since pc was always the first
  1069.          * register) but it probably printed some wrong values.
  1070.          */
  1071.         nreg++;
  1072.         } /* if */
  1073.     } /* for */
  1074.     if (ppd->pcreg == 0)
  1075.         pc = (*getword)(fp-4);
  1076.     else
  1077.         pc = regs[31];
  1078.     } /* for */
  1079.     ldaclose(ldptr);
  1080.     return 0;
  1081. } /* stacktrace */
  1082.  
  1083.  
  1084. int static
  1085. ipd_adr (ldptr, adr)
  1086. LDFILE *ldptr;
  1087. unsigned long adr;
  1088.  
  1089. {
  1090.     int        ilow;
  1091.     int        ihigh;
  1092.     int        ihalf;
  1093.     int        ilowold;
  1094.     int        ihighold;
  1095.     int        ipd;
  1096.     PDR        apd;
  1097.  
  1098.  
  1099.     ilow = 0;
  1100.     ihigh = SYMHEADER(ldptr).ipdMax;
  1101.     /* binary search proc table */
  1102.     while (ilow < ihigh) {
  1103.     ihalf = (ilow + ihigh) / 2;
  1104.     ilowold = ilow;
  1105.     ihighold = ihigh;
  1106.     ldgetpd(ldptr, ihalf, &apd);
  1107.     if (adr < apd.adr)
  1108.         ihigh = ihalf;
  1109.     else if (adr > apd.adr)
  1110.         ilow = ihalf;
  1111.     else {
  1112.         ilow = ihigh = ihalf;
  1113.         break;
  1114.     } /* if */
  1115.     if (ilow == ilowold && ihigh == ihighold)
  1116.         break;
  1117.     } /* while */
  1118.  
  1119.     ipd =  ((ilow < ihigh || ihigh < 0) ? ilow : ihigh);
  1120.  
  1121.     return (ipd);
  1122.  
  1123. } /* ipd_adr */
  1124.  
  1125. /*
  1126.     Get symbol table value of first extern function in the object file.
  1127.     Get its name.
  1128.     Ask rld for the address of that name.
  1129.     Offset is the address minus the symbol table value.
  1130. */
  1131. #ifdef IRIX5
  1132. static long
  1133. get_ldptr_offset(LDFILE *ldptr)
  1134. {
  1135.     int ilow, ihigh, i;
  1136.     unsigned long symbol_table_value, address_in_memory;
  1137.     struct pdr pd;
  1138.     SYMR asym;
  1139.     char *name;
  1140.  
  1141.     ilow = 0;
  1142.     ihigh = SYMHEADER(ldptr).ipdMax;
  1143.     for (i = ilow; i <= ihigh; ++i) {
  1144.         if (ldgetpd(ldptr, i, &pd) == FAILURE) {
  1145.         fprintf(stderr, "\nget_ldptr_offset: ldgetpd(i=%d) failed!\n", i);
  1146.         return 0;
  1147.         }
  1148.  
  1149.     if (pd.isym == -1) {
  1150.         fprintf(stderr, "\nget_ldptr_offset: pd.isym == -1!\n");
  1151.         return 0;
  1152.     }
  1153.     if (ldtbread(ldptr,pd.isym,&asym) == FAILURE) {
  1154.         fprintf(stderr, "\nget_ldptr_offset: ldtbread failed!\n");
  1155.         return 0;
  1156.     }
  1157.     /* XXX should move this down below, but need name for diagnostic msg */
  1158.     if ((name = (char *)ldgetname(ldptr, &asym)) == NULL) {
  1159.         fprintf(stderr, "\nget_ldptr_offset: ldgetname failed!\n");
  1160.         return 0;
  1161.     }
  1162.  
  1163.     if (asym.st != stProc) {
  1164.         if (getenv("_STACKTRACE_LDPTR_DEBUG"))
  1165.         fprintf(stderr, "(%s isn't a global procedure; going on to next)\n", name);
  1166.         continue;
  1167.     }
  1168.     break;
  1169.     }
  1170.  
  1171.     if (i > ihigh) {
  1172.     fprintf(stderr, "\nget_ldptr_offset: everything was static??\n");
  1173.     return 0;
  1174.     }
  1175.  
  1176.     if (getenv("_STACKTRACE_LDPTR_DEBUG"))
  1177.     fprintf(stderr, "get_ldptr_offset: getting offset by comparing address with symbol value of \"%s\"\n", name);
  1178.  
  1179.     symbol_table_value = pd.adr;
  1180.     address_in_memory = (unsigned long) _rld_new_interface(_RLD_NAME_TO_ADDR, name);
  1181.  
  1182.     if (address_in_memory == 0) {
  1183.     fprintf(stderr, "(couldn't figure out delta, assuming 0) ");
  1184.     return 0;
  1185.     }
  1186.  
  1187.     if (address_in_memory != symbol_table_value) {
  1188.     fprintf(stderr, "\n======= SURPRISE! ======\n");
  1189.     fprintf(stderr, "\tValue of %s in file is %#x, in memory it's %#x\n",
  1190.         name, symbol_table_value, address_in_memory);
  1191.     }
  1192.  
  1193.     return address_in_memory - symbol_table_value;
  1194. }
  1195. #endif /* IRIX5 */
  1196.  
  1197. /*
  1198.  * Search through all objects in the ldptrs array
  1199.  * looking for the procedure which adr falls inside.
  1200.  * Returns the procedure index, and sets *Whichldptr to
  1201.  * the ldptr it was found in.
  1202.  *
  1203.  * XXX this is WRONG-- this assumes that a procedure's
  1204.  * address in memory is the same as the value of the corresponding symbol.
  1205.  * This seems to be true in every case I've seen so far (the values
  1206.  * in a given .so begin at a seemingly arbitrary address, and none
  1207.  * of them happen to overlap), but obviously this is unreliable.
  1208.  * I assume that if the addresses of two .so's overlap, then
  1209.  * rld relocates one of them to a new area; I don't know how this
  1210.  * works, and I've never seen it happen.
  1211.  *
  1212.  * (actually, now I try to calculate the offset, but it doesn't quite work yet
  1213.  * for dlopened objects, and I've never seen it in action...)
  1214.  * 
  1215.  * XXX should make a better procedure that doesn't duplicate work
  1216.  */
  1217. int static
  1218. ipd_adr_all(nldptrs, ldptrs, ldoffsets, Whichldptr, Whichoffset, adr)
  1219. int nldptrs;
  1220. LDFILE *ldptrs[], **Whichldptr;
  1221. long ldoffsets[], *Whichoffset;
  1222. address adr;
  1223. {
  1224.     int i;
  1225.     PDR pd;
  1226.  
  1227.     assert(nldptrs > 0);
  1228.     for (i = 0; i < nldptrs; ++i) {
  1229.     ldgetpd(ldptrs[i], 0, &pd);
  1230.     if (adr < pd.adr + ldoffsets[i])
  1231.         continue;
  1232.     ldgetpd(ldptrs[i], SYMHEADER(ldptrs[i]).ipdMax-1, &pd);
  1233. #define ROUNDUP(a,b) (((a)+(b)-1)/(b)*(b)) /* round up a to a multiple of b */
  1234.     if (adr > ROUNDUP((unsigned)pd.adr+1,4096) + ldoffsets[i])
  1235.            /* XXX WRONG WRONG WRONG!!!!!! */
  1236.            /* NEED TO FIND THE ADDRESS OF THE END OF THE LAST PROCEDURE!! */
  1237.         continue;
  1238.     *Whichldptr = ldptrs[i];
  1239.     *Whichoffset = ldoffsets[i];
  1240.     return ipd_adr(*Whichldptr, adr - ldoffsets[i]) + ldoffsets[i];
  1241.     }
  1242.     /* do something arbitrary if we are totally lost */
  1243.     i = 0;
  1244.     if (nldptrs >= 2 && !SYMTAB(ldptrs[i]))
  1245.     i = 1;
  1246.     *Whichldptr = ldptrs[i];
  1247.     *Whichoffset = ldoffsets[i];
  1248.     return ipd_adr(*Whichldptr, adr - ldoffsets[i]) + ldoffsets[i];
  1249. }
  1250.  
  1251. void static
  1252. dumpscp(scp)
  1253. register struct sigcontext *scp;
  1254. {
  1255.     register int i, j;
  1256.  
  1257.     myprintf("sigcontext\n");
  1258.     myprintf("PC: 0x%08x, CAUSE: 0x%08x, BADVADDR: 0x%08x\n",
  1259.         scp->sc_pc, scp->sc_cause, scp->sc_badvaddr);
  1260.  
  1261.     myprintf("OWNEDFP: %d, FP_CSR: 0x%08x\n", scp->sc_ownedfp,
  1262.         scp->sc_fpc_csr);
  1263.  
  1264.     if (scp->sc_ownedfp == 0)
  1265.         return;
  1266.     myprintf("fp regs\n");
  1267.     for (i = 0; i < 32; i += 4) {
  1268.         for (j = i; j < i+4; j++)
  1269.             myprintf("%2d: 0x%08x\t", j, scp->sc_fpregs[j]);
  1270.         myprintf("\n");
  1271.     }
  1272. }
  1273.  
  1274. void static
  1275. handler(sig, code, scp)
  1276. int sig, code;
  1277. struct sigcontext *scp;
  1278. {
  1279.     int regs[32];
  1280.     int i;
  1281.  
  1282.     switch(sig){
  1283.     case SIGSEGV:
  1284.         myprintf("SIGSEGV signal caught\n");
  1285.         break;
  1286.     case SIGBUS:
  1287.         myprintf("SIGBUS signal caught\n");
  1288.         break;
  1289.     case SIGILL:
  1290.         myprintf("SIGILL signal caught\n");
  1291.         break;
  1292.     case SIGQUIT:
  1293.         myprintf("SIGQUIT signal caught\n");
  1294.         break;
  1295.     default:
  1296.         myprintf("Unknown signal caught: signo = %d\n",sig);
  1297.         break;
  1298.     }
  1299.     if (getenv("_STACKTRACE_DONT_TRACE"))
  1300.         return;
  1301.  
  1302.     dumpscp(scp);
  1303.     /* XXX ARGH-- evidently this messes up the stack, so can't return */
  1304.  
  1305.     /* in sherwood, scp->sc_regs is an array of 64-bit quantities,
  1306.        but the stacktrace program is old and expects an array of ints. */
  1307.     for (i = 0; i < 32; ++i)
  1308.         regs[i] = (int)*(long long *)&scp->sc_regs[i];
  1309.  
  1310.     stacktrace(myname,
  1311.            (int)*(int *)&scp->sc_pc,
  1312.            (int)*(int *)&scp->sc_regs[GPR_BASE+29],
  1313.            regs,
  1314.            agetword);
  1315.     if (sig != SIGQUIT)
  1316.         exit(sig);
  1317. }
  1318.  
  1319. #ifdef NOTUSED
  1320. static int myfd;
  1321.  
  1322. ugmyprintf(format, a, b, c, d)
  1323. char *format;
  1324. {
  1325.     char buf[512];
  1326.  
  1327.     sprintf (buf, format, a, b, c, d);
  1328.     write(myfd, buf, strlen(buf));
  1329. }
  1330. #endif /* NOTUSED */
  1331.  
  1332. #ifdef __cplusplus
  1333. typedef void (*sigret)(...);
  1334. #else
  1335. typedef void (*sigret)();
  1336. #endif
  1337.  
  1338. extern void
  1339. initstacktrace(argv)
  1340. char **argv;
  1341. {
  1342.  
  1343.     
  1344. #ifdef NOTUSED
  1345.     myfd = open("/dev/tty", O_RDWR);
  1346.     if (myfd < 0)
  1347.     perror("initstacktrace cannot open /dev/tty");
  1348. #endif /* NOTUSED */
  1349.  
  1350.     struct sigcontext *scp;
  1351.  
  1352.     scp = NULL;    /* suppress stupid compiler warning */
  1353.  
  1354.     if (BITS(scp->sc_regs[0]) != 32 && !getenv("_TRY_SHERWOOD_STACKTRACE")) {
  1355.     /* fprintf(stderr, "Can't init signal handler to do stack traces \non SEGV and BUS (but I still love sherwood)\n"); */
  1356.     return;
  1357.     }
  1358.  
  1359.     if (argv)
  1360.     myname = argv[0];
  1361.     else
  1362.     myname = stacktrace_get_executable();
  1363.     signal(SIGSEGV, (sigret)handler);
  1364.     signal(SIGBUS, (sigret)handler);
  1365.     signal(SIGILL, (sigret)handler);
  1366.     signal(SIGQUIT, (sigret)handler);
  1367. }
  1368. /*================== End stuff I found in old dbx source ==================*/
  1369.